/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.meta.component;

import com.alibaba.druid.pool.DruidDataSource;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.je.common.base.exception.PlatformException;
import com.je.common.base.exception.PlatformExceptionEnum;
import com.je.common.base.service.MetaResourceService;
import com.je.common.base.spring.SpringContextHolder;
import com.je.common.base.util.StringUtil;
import org.apache.servicecomb.core.BootListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;


public class ThirdDataSourceStarter implements BootListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(ThirdDataSourceStarter.class);

    /**
     * 查询数据源语句
     */
    private static final String SQL = "select THIRDSOURCE_MC as DSNAME,THIRDSOURCE_LJC_CODE AS POOLTYPE,THIRDSOURCE_DB_CODE as DIALECT,THIRDSOURCE_LJPZ AS URL,THIRDSOURCE_USERNAME AS USERNAME,THIRDSOURCE_PASSWORD AS USERPASSWORD,THIRDSOURCE_ZXLJS AS MINSIZE, THIRDSOURCE_ZDLJS AS MAXSIZE, THIRDSOURCE_CSSQL AS TESTSQL from JE_CORE_THIRDSOURCE where THIRDSOURCE_SFQY_CODE = '1' AND THIRDSOURCE_MC in (%s)";

    @Override
    public int getOrder() {
        return 1001;
    }

    @Override
    public void onAfterRegistry(BootEvent event) {
        MetaResourceService metaResourceService = SpringContextHolder.getBean(MetaResourceService.class);
        Environment environment = SpringContextHolder.getBean(Environment.class);
        try {
            //获取数据源
            String configDataSource = environment.getProperty("jecloud.dataSources");
            if(Strings.isNullOrEmpty(configDataSource)){
                return;
            }

            List<String> dataSourceNames = Splitter.on(",").splitToList(configDataSource);
            List<Map<String, Object>> list = metaResourceService.selectMap(String.format(SQL, StringUtil.buildArrayToString(dataSourceNames)));

            if (list == null || list.isEmpty()) {
                return;
            }

            //加入IOC
            list.forEach(map -> {

                String poolType = map.get("POOLTYPE").toString();
                String name = map.get("DSNAME").toString();
                String dialect = map.get("DIALECT").toString();
                String url = map.get("URL").toString();
                String userName = map.get("USERNAME").toString();
                String password = map.get("USERPASSWORD").toString();
                String testSql = map.get("TESTSQL").toString();
                String minIdle = map.get("MINSIZE").toString();
                String maxActive = map.get("MAXSIZE").toString();

                if (!"druid".equals(poolType.toLowerCase())) {
                    LOGGER.error("暂时不支持此类型数据源 {}", poolType);
                    return;
                }
                Map<String, Object> beanMap = new HashMap<>(32);
                beanMap.put("validationQuery", "SELECT 1");
                if ("sqlserver".equals(dialect)) {
                    beanMap.put("driverClassName", "com.microsoft.sqlserver.jdbc.SQLServerDriver");
                } else if ("mysql".equals(dialect)) {
                    beanMap.put("driverClassName", "com.mysql.jdbc.Driver");
                } else if ("tidb".equals(dialect)) {
                    beanMap.put("driverClassName", "com.mysql.jdbc.Driver");
                } else if ("oracle".equals(dialect)) {
                    beanMap.put("driverClassName", "oracle.jdbc.OracleDriver");
                    beanMap.put("validationQuery", "SELECT 1 FROM DUAL");
                } else if ("oscar".equals(dialect)) {
                    beanMap.put("driverClassName", "com.oscar.Driver");
                } else if ("kingbase8".equals(dialect)) {
                    beanMap.put("driverClassName", "com.kingbase8.Driver");
                } else if ("dm".equals(dialect)) {
                    beanMap.put("driverClassName", "dm.jdbc.driver.DmDriver");
                } else {
                    throw new PlatformException("暂时不支持此类型数据库", PlatformExceptionEnum.JE_CORE_DSFDB_UNKOWN_ERROR);
                }
                beanMap.put("validationQuery", testSql);
                beanMap.put("url", url);
                beanMap.put("username", userName);
                beanMap.put("password", password);
                beanMap.put("initialSize", "5");
                beanMap.put("minIdle", minIdle);
                beanMap.put("maxActive", maxActive);
                beanMap.put("maxWait", "60000");
                beanMap.put("timeBetweenEvictionRunsMillis", "60000");
                beanMap.put("minEvictableIdleTimeMillis", "200000");
                beanMap.put("testWhileIdle", "true");
                beanMap.put("testOnBorrow", "true");
                beanMap.put("testOnReturn", "false");
                beanMap.put("poolPreparedStatements", "true");
                beanMap.put("maxPoolPreparedStatementPerConnectionSize", "20");
                beanMap.put("defaultAutoCommit", "true");
                beanMap.put("validationQueryTimeout", "600");
                beanMap.put("removeAbandoned", "true");
                beanMap.put("removeAbandonedTimeout", "1800");
                beanMap.put("logAbandoned", "false");
                dynamiRegistBean(name, DruidDataSource.class, beanMap);
            });

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void dynamiRegistBean(String beanName, Class<?> clazz, Map<String, Object> attrs) {
        ApplicationContext applicationContext = SpringContextHolder.getApplicationContext();
        // 获取BeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();

        BeanDefinitionBuilder beanDefBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
        BeanDefinition beanDef = beanDefBuilder.getBeanDefinition();
        Set<String> keys = attrs.keySet();
        for (String attrName : keys) {
            beanDef.getPropertyValues().add(attrName, attrs.get(attrName));
        }

        defaultListableBeanFactory.registerBeanDefinition(beanName,beanDef);

        if (!defaultListableBeanFactory.containsBeanDefinition(beanName)) {
            defaultListableBeanFactory.registerBeanDefinition(beanName, beanDef);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.info("已经注册了【" + beanName + "】");
            }
        } else {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.info("已经存在了【" + beanName + "】");
            }

        }
    }

}
